using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;
using digit.Core;

namespace UserManager
{
    public static class Encryption
    {
        static Encryption() { }

        #region Hash Algorithm Methods
        public static string MACTripleDESHash(string value, string key)
        {
            return Encryption.KeyHash<KeyedHashAlgorithm>(value, key, MACTripleDES.Create());
        }

        public static string MD5Hash(string value)
        {
            return Encryption.Hash<MD5>(value, MD5.Create());
        }

        public static string MD5Encrypt(string source)
        {
            if (Util.IsNull(source)) return "";

            byte[] clearBytes = Encoding.Unicode.GetBytes(source);
            MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
            byte[] hashBytes = md5.ComputeHash(clearBytes);

            return BitConverter.ToString(hashBytes).Replace("-", "");
        }

        public static string RIPEMD160Hash(string value)
        {
            return Encryption.Hash<RIPEMD160>(value, RIPEMD160.Create());
        }

        public static string SHA1Hash(string value)
        {
            return Encryption.Hash<SHA1>(value, SHA1.Create());
        }

        public static string SHA512Hash(string value)
        {
            return Encryption.Hash<SHA512>(value, SHA512.Create());
        }
        #endregion

        #region Symmetric Algorithm Methods
        public static string DESEncrypt(string value)
        {
            return Encryption.Symmetric<DES>(value, DES.Create(), true);
        }

        public static string DESEncrypt(string value, ref string key, ref string iv)
        {
            if (string.IsNullOrEmpty(key)) key = RandomCode.RamdomString(24);
            if (string.IsNullOrEmpty(iv)) iv = RandomCode.RamdomString(16);

            return Encryption.Symmetric<DES>(value, DES.Create(), key, iv, true);
        }

        public static string DESDecrypt(string value)
        {
            return Encryption.Symmetric<DES>(value, DES.Create(), false);
        }

        public static string DESDecrypt(string value, string key, string iv)
        {
            return Encryption.Symmetric<DES>(value, DES.Create(), key, iv, false);
        }

        public static string RC2Encrypt(string value)
        {
            return Encryption.Symmetric<RC2>(value, RC2.Create(), true);
        }

        public static string RC2Encrypt(string value, ref string key, ref string iv)
        {
            if (string.IsNullOrEmpty(key)) key = RandomCode.RamdomString(24);
            if (string.IsNullOrEmpty(iv)) iv = RandomCode.RamdomString(16);

            return Encryption.Symmetric<RC2>(value, RC2.Create(), key, iv, true);
        }

        public static string RC2Decrypt(string value)
        {
            return Encryption.Symmetric<RC2>(value, RC2.Create(), false);
        }

        public static string RC2Decrypt(string value, string key, string iv)
        {
            return Encryption.Symmetric<RC2>(value, RC2.Create(), key, iv, false);
        }

        public static string RijndaelEncrypt(string value)
        {
            return Encryption.Symmetric<Rijndael>(value, Rijndael.Create(), true);
        }

        public static string RijndaelEncrypt(string value, ref string key, ref string iv)
        {
            if (string.IsNullOrEmpty(key)) key = RandomCode.RamdomString(24);
            if (string.IsNullOrEmpty(iv)) iv = RandomCode.RamdomString(16);

            return Encryption.Symmetric<Rijndael>(value, Rijndael.Create(), key, iv, true);
        }

        public static string RijndaelDecrypt(string value)
        {
            return Encryption.Symmetric<Rijndael>(value, Rijndael.Create(), false);
        }

        public static string RijndaelDecrypt(string value, string key, string iv)
        {
            return Encryption.Symmetric<Rijndael>(value, Rijndael.Create(), key, iv, false);
        }

        public static string TripleDESEncrypt(string value)
        {
            return Encryption.Symmetric<TripleDES>(value, TripleDES.Create(), true);
        }

        public static string TripleDESEncrypt(string value, ref string key, ref string iv)
        {
            if (string.IsNullOrEmpty(key)) key = RandomCode.RamdomString(24);
            if (string.IsNullOrEmpty(iv)) iv = RandomCode.RamdomString(16);

            return Encryption.Symmetric<TripleDES>(value, TripleDES.Create(), key, iv, true);
        }

        public static string TripleDESDecrypt(string value)
        {
            return Encryption.Symmetric<TripleDES>(value, TripleDES.Create(), false);
        }

        public static string TripleDESDecrypt(string value, string key, string iv)
        {
            return Encryption.Symmetric<TripleDES>(value, TripleDES.Create(), key, iv, false);
        }
        #endregion

        #region Generic Call Algorithm Methods
        public static string Hash<TCrypto>(string value, TCrypto hashCrypto)
            where TCrypto : HashAlgorithm
        {
            if (string.IsNullOrEmpty(value)) value = RandomCode.RamdomString(16);
            byte[] bRaw = UnicodeEncoding.Unicode.GetBytes(value);
            string strCrypt = Convert.ToBase64String(hashCrypto.ComputeHash(bRaw));
            return strCrypt.Replace("-", "");
        }

        public static string KeyHash<TCrypto>(string value, TCrypto hashCrypto)
            where TCrypto : KeyedHashAlgorithm
        {
            byte[] bKey = RandomCode.RandomBytes(64);
            return Encryption.KeyHash<TCrypto>(value, bKey, hashCrypto);
        }

        public static string KeyHash<TCrypto>(string value, string key, TCrypto hashCrypto)
            where TCrypto : KeyedHashAlgorithm
        {
            byte[] bKey = Convert.FromBase64String(key);
            return Encryption.KeyHash<TCrypto>(value, bKey, hashCrypto);
        }

        public static string KeyHash<TCrypto>(string value, byte[] key, TCrypto hashCrypto)
            where TCrypto : KeyedHashAlgorithm
        {
            hashCrypto.Key = key;
            return Encryption.Hash<TCrypto>(value, hashCrypto);
        }

        public static string Symmetric<TCrypto>(string value, TCrypto hashCrypto, bool encryptMode)
            where TCrypto : SymmetricAlgorithm
        {
            using (MemoryStream ms = new MemoryStream())
            {
                CryptoStream cs;
                if (encryptMode) cs = new CryptoStream(ms, hashCrypto.CreateEncryptor(), CryptoStreamMode.Write);
                else cs = new CryptoStream(ms, hashCrypto.CreateDecryptor(), CryptoStreamMode.Write);

                StreamWriter sw = new StreamWriter(cs);
                sw.Write(value);
                sw.Close();
                cs.Close();

                byte[] bCrypto = ms.ToArray();
                ms.Close();
                return Convert.ToBase64String(bCrypto).Replace("-", "");
            }
        }

        public static string Symmetric<TCrypto>(string value, TCrypto hashCrypto, byte[] key, byte[] iv, bool encryptMode)
            where TCrypto : SymmetricAlgorithm
        {
            using (MemoryStream ms = new MemoryStream())
            {
                CryptoStream cs;
                if (encryptMode) cs = new CryptoStream(ms, hashCrypto.CreateEncryptor(key, iv), CryptoStreamMode.Write);
                else cs = new CryptoStream(ms, hashCrypto.CreateDecryptor(key, iv), CryptoStreamMode.Write);

                StreamWriter sw = new StreamWriter(cs);
                sw.Write(value);
                sw.Close();
                cs.Close();

                byte[] bCrypto = ms.ToArray();
                ms.Close();
                return Convert.ToBase64String(bCrypto).Replace("-", "");
            }
        }

        public static string Symmetric<TCrypto>(string value, TCrypto hashCrypto, string key, string iv, bool encryptMode)
            where TCrypto : SymmetricAlgorithm
        {
            byte[] bKeys = UnicodeEncoding.Unicode.GetBytes(key);
            byte[] bIV = UnicodeEncoding.Unicode.GetBytes(iv);

            return Encryption.Symmetric<TCrypto>(value, hashCrypto, bKeys, bIV, encryptMode);
        }
        #endregion

        #region Convert Character Methods
        public static byte[] StringToBytes(string value)
        {
            return UnicodeEncoding.Unicode.GetBytes(value);
        }
        #endregion
    }
}
